<template>
	<div class="card table-search">
		<el-form
			ref="searchFormRef"
			:model="value"
			:label-width="searchLabelWidth"
			class="table-search-form"
			inline
			@submit.prevent
			@keyup.enter="keyupHandle"
		>
			<div
				:style="{
					minHeight: state.formCollapseHeight + 'px',
					maxHeight: state.collapse ? state.formCollapseHeight + 'px' : '500px',
					overflow: state.collapse ? 'hidden' : 'auto',
					transition: 'max-height 0.3s'
				}"
			>
				<div ref="formContentRef" class="formContent">
					<el-form-item class="operation" label-width="0px">
						<CSearchOperation
							:show-collapse="state.showCollapse"
							v-model:collapse="state.collapse"
							:showQueryButton="true"
							@search="search"
							@reset="reset"
						/>
					</el-form-item>
					<el-form-item v-for="item in searchItems" :key="item.prop" :prop="item.prop">
						<template #label>
							<span>
								{{ item.label
								}}<el-tooltip v-if="item.alert" effect="dark" :content="item.alert" placement="top">
									<el-icon><InfoFilled /></el-icon>
								</el-tooltip>
							</span>
						</template>
						<div :style="{ width: item.searchWidth || componentInfo(item).width, height: '38px' }">
							<slot :name="'search_' + item.prop" v-bind="{ searchParam: value, prop: item.prop, data: item }">
								<!-- <el-input v-model.trim="value[item.prop!]" clearable /> -->
								<component :is="componentIs(item)" v-model="value[item.prop!]" v-bind="componentProps(item)"></component>
							</slot>
						</div>
					</el-form-item>
				</div>
			</div>
		</el-form>
	</div>
</template>

<script setup lang="ts" name="CSearch">
import { ref, reactive, computed, watch, onUnmounted, nextTick } from 'vue'
// 导入兼容模块
import ResizeObserver from 'resize-observer-polyfill'
import CSearchOperation from './components/CSearchOperation/index.vue'
import { ColumnProps, SearchType } from '@/components/CTable/interface'
import { InfoFilled } from '@element-plus/icons-vue'
export type SearchTriggerMode = 'button' | 'changeEvent'
// 默认值
const props = withDefaults(
	defineProps<{
		searchLabelWidth?: string // 搜索 label 宽度
		searchItems: ColumnProps[] // 搜索字段
		modelValue?: Record<string, any> // searchParam
		reset?: Function // 重置方法
		searchTriggerMode?: SearchTriggerMode // 搜索触发模式
	}>(),
	{
		searchLabelWidth: '100px',
		searchTriggerMode: 'changeEvent',
		modelValue: () => ({})
	}
)
const emits = defineEmits(['update:modelValue', 'search', 'reset'])

// 按钮和回车触发模式
const isButtonMode = computed(() => props.searchTriggerMode === 'button')
// change事件触发模式
const isChangeEventMode = computed(() => props.searchTriggerMode === 'changeEvent')
// vmodel
const value = computed({
	get() {
		return props.modelValue
	},
	set(newVal: any) {
		emits('update:modelValue', newVal)
	}
})

let state = reactive({
	// 是否折叠
	collapse: true,
	showCollapse: true,
	// form 折叠高度
	formCollapseHeight: 56,
	// form 高度
	formHeight: 0
})
/* 监听 resize 变化 */
const formContentRef = ref()
const handleResize = () => {
	if (formContentRef.value) {
		state.formHeight = formContentRef.value.getBoundingClientRect().height
		// 10 是误差值，getBoundingClientRect 获取的值有时会有误差，如果换行了也不止 10，所以不会有问题
		state.showCollapse = state.formHeight - state.formCollapseHeight > 10
	}
}
const resizeObserver = new ResizeObserver(handleResize)
onUnmounted(() => {
	resizeObserver.disconnect()
})

watch(
	() => props.searchItems,
	() => {
		/* 构建搜索 */
		const searchParam: Record<string, any> = {}
		for (let index = 0; index < props.searchItems.length; index++) {
			const e = props.searchItems[index]
			searchParam[e.prop!] = e.searchDefault ?? value.value[e.prop!] ?? null
		}
		// console.log(props.searchItems, searchParam, value.value)
		// debugger
		value.value = searchParam
		// Object.assign(value.value, searchParam)
		/* 监听大学改变 */
		resizeObserver.disconnect()
		if (props.searchItems && props.searchItems.length) {
			nextTick(() => {
				handleResize()
				resizeObserver.observe(formContentRef.value)
			})
		}
	},
	{ immediate: true }
)

const searchFormRef = ref()
/** 查询列表 */
const search = () => {
	emits('search', value.value)
}
/**回车 */
const keyupHandle = () => {
	// 只有是按钮触发模式回车才会触发搜索
	if (isButtonMode.value) {
		search()
	}
}
/** 重置 */
const reset = () => {
	if (props.reset) {
		props.reset(searchFormRef.value)
	} else {
		searchFormRef.value.resetFields()
		search()
	}
	emits('reset', value.value)
}
/* 组件信息 */
const componentInfo = (item: ColumnProps): any => {
	const options = item._dictData
	/* 组件映射，此对象放里面方便后面根据 item 数据修改*/
	const compMap: Record<SearchType, any> = {
		input: {
			componentName: 'el-input',
			width: '210px',
			props: {
				placeholder: '请输入',
				clearable: true
			}
		},
		number: {
			componentName: 'el-input-number',
			width: '210px',
			props: {
				min: 1,
				placeholder: '请输入',
				controlsPosition: 'right'
			}
		},
		switch: {
			componentName: 'el-switch',
			width: '210px',
			props: {}
		},
		select: {
			componentName: 'DictSelect',
			width: '210px',
			props: {
				options,
				placeholder: '请选择',
				clearable: true
			}
		},
		multipleSelect: {
			componentName: 'DictSelect',
			width: '210px',
			props: {
				options,
				placeholder: '请选择',
				clearable: true,
				multiple: true
			}
		},
		treeSelect: {
			componentName: 'el-tree-select',
			width: '210px',
			props: {
				placeholder: '请选择',
				clearable: true
			}
		},
		multipleTreeSelect: {
			componentName: 'el-tree-select',
			width: '210px',
			props: {
				placeholder: '请选择',
				clearable: true,
				multiple: true
			}
		},
		date: {
			componentName: 'el-date-picker',
			width: '210px',
			props: {
				type: 'date',
				valueFormat: 'YYYY-MM-DD',
				placeholder: '请选择日期',
				clearable: true
			}
		},
		daterange: {
			componentName: 'el-date-picker',
			width: '520px',
			props: {
				type: 'daterange',
				valueFormat: 'YYYY-MM-DD',
				rangeSeparator: '至',
				startPlaceholder: '开始时间',
				endPlaceholder: '结束时间',
				clearable: true
			}
		},
		time: {
			componentName: 'el-time-picker',
			width: '210px',
			props: {
				placeholder: '请选择时间',
				clearable: true
			}
		},
		timerange: {
			componentName: 'el-time-picker',
			width: '520px',
			props: {
				isRange: true,
				rangeSeparator: '至',
				startPlaceholder: '开始时间',
				endPlaceholder: '结束时间',
				clearable: true
			}
		},
		datetime: {
			componentName: 'el-date-picker',
			width: '210px',
			props: {
				type: 'datetime',
				valueFormat: 'YYYY-MM-DD HH:mm:ss',
				placeholder: '请选择时间',
				clearable: true
			}
		},
		datetimerange: {
			componentName: 'el-date-picker',
			width: '520px',
			props: {
				type: 'datetimerange',
				valueFormat: 'YYYY-MM-DD HH:mm:ss',
				rangeSeparator: '至',
				startPlaceholder: '开始时间',
				endPlaceholder: '结束时间',
				clearable: true
			}
		}
	}

	let result
	if (item.searchType) {
		result = compMap[item.searchType]
	} else {
		// 默认
		result = compMap.input
	}

	return result
}
const componentProps = (item: ColumnProps): any => {
	let props = componentInfo(item).props
	// change 事件触发模式
	if (isChangeEventMode.value) {
		props = {
			onChange() {
				search()
			},
			...props
		}
	}
	return {
		...props,
		...item.searchProps
	}
}
const componentIs = (item: ColumnProps): string => {
	return componentInfo(item).componentName
}
</script>
<style scoped lang="scss">
.table-search {
	padding: 22px 22px 0;
	background-color: var(--el-fill-color-blank);
	border: 1px solid var(--el-border-color-light);
	.el-form-item {
		margin-right: 5px;
		.el-input,
		.el-select,
		.el-date-editor--timerange {
			width: 100%;
		}
		.el-date-editor--datetimerange,
		.el-date-editor--daterange {
			width: 380px;
		}

		// 去除时间选择器上下 padding
		.el-range-editor.el-input__wrapper {
			padding: 0 10px;
		}

		// el-select 为多选时不换行显示
		.el-select__tags {
			overflow: hidden;
			white-space: nowrap;
		}
	}

	// .el-form-item {
	//   display: inherit;
	// }
	.operation {
		float: right;
		:deep(.operation-container) {
			// width: 215px;
		}
	}
}
</style>
